package graphen;

import java.awt.BasicStroke;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import javax.swing.JPanel;
import javax.swing.JFrame;
import java.awt.Graphics;
import java.awt.Color;
import graphen.struktur.*;

public class Labyrinth extends JPanel implements MouseListener, MouseMotionListener{
  /* Die Ränder gehen über das Feld hinaus, um die ifs einfacher zu halten.
   *     |   |   |   |     Das hier ist ein Labyrinth(2,3).
   *   --+---+---+---+--
   *     |1,1|1,2|1,3|
   *   --+---+---+---+--
   *     |2,1|2,2|2,3|
   *   --+---+---+---+--
   *     |   |   |   |
   */
  static final int D=15; //die Breite und Höhe der Zellen in Pixeln
  boolean[][] waag; //erster  Index = Zeilennummer
  boolean[][] senk; //zweiter Index = Spaltennummer
  int zeilen, spalten;
  Graph graph;
  Graph.Plan plan;

  public Labyrinth(int zeilen, int spalten){
    this.zeilen=zeilen;
    this.spalten=spalten;
    waag=new boolean[zeilen+1][spalten+2];
    senk=new boolean[zeilen+2][spalten+1];
    this.setPreferredSize(new Dimension(D*spalten,D*zeilen));
    macheWege();
    graph=getGraph();
    addMouseListener(this);
    addMouseMotionListener(this);
  }

  public void macheWege(){
    // erst mal alle Wände setzen
    for(int j=0; j<=spalten; ++j)
      senk[zeilen+1][j]=true;
    for(int i=0; i<=zeilen;  ++i){
      for(int j=0; j<=spalten; ++j){
        senk[i][j]=true;
        waag[i][j]=true;
      }
      waag[i][spalten+1]=true;
    }
    // jetzt viele aber nicht zu viele wieder entfernen
    int kasten, kreuz;
    for(int z=1; z<=zeilen; ++z){
      for(int s=1; s<=spalten; ++s){
        /*kasten=((senk[z][s-1]?1:0)+(senk[z][s]?1:0)
             +(waag[z-1][s]?1:0)+(waag[z][s]?1:0));*/
        kreuz =((senk[z-1][s]?1:0)+(senk[z][s]?1:0)
             +(waag[z-1][s]?1:0)+(waag[z-1][s+1]?1:0));
        // soll rechts weg?
        if(kreuz/5.0>Math.random() && s<spalten && kreuz>1)
          senk[z][s]=false;
        kasten=((senk[z][s-1]?1:0)+(senk[z][s]?1:0)
             +(waag[z-1][s]?1:0)+(waag[z][s]?1:0));
        kreuz =((senk[z][s-1]?1:0)+(senk[z+1][s-1]?1:0)
             +(waag[z][s-1]?1:0)+(waag[z][s]?1:0));
        // soll unten weg?
        if(kasten/4.0>Math.random() && z<zeilen && kreuz>1)
          waag[z][s]=false;
      }
    }
  }

  public Graph getGraph(){
    Graph g=new Graph();
    for(int z=1; z<=zeilen; ++z)
      for(int s=1; s<=spalten; ++s)
        g.addKnoten(z+","+s);
    for(int z=1; z<=zeilen; ++z)
      for(int s=1; s<=spalten; ++s){
        if(!senk[z][s])   g.addKante(z+","+s,     z+","+(s+1),1); //rechts
        if(!senk[z][s-1]) g.addKante(z+","+s,     z+","+(s-1),1); //links
        if(!waag[z][s])   g.addKante(z+","+s, (z+1)+","+s    ,1); //unten
        if(!waag[z-1][s]) g.addKante(z+","+s, (z-1)+","+s    ,1); //oben
      }
    return g;
  }

  private int zielnr;
  private BasicStroke stroke=new BasicStroke(4);
  @Override
  public void paint(Graphics g){
    super.paint(g);
    Graphics2D g2=(Graphics2D)g;
    // zeichne waagrechte Linien
    for(int z=0; z<=zeilen; ++z)
      for(int s=1; s<=spalten; ++s)
        if(waag[z][s]) g.drawLine((s-1)*D,z*D,s*D,z*D);
    // zeichne senkrechte Linien
    for(int z=1; z<=zeilen; ++z)
      for(int s=0; s<=spalten; ++s)
        if(senk[z][s]) g.drawLine(s*D,(z-1)*D,s*D,z*D);
    if(plan!=null){
      int[] weg=plan.getWegNach(zielnr);
      int anz=weg.length;
      g.setColor(Color.BLUE);
      g2.setStroke(stroke);
      int x0, y0, next;
      next=plan.getStartNr();
      y0=next/spalten;
      x0=next%spalten;
      g.fillOval(D*x0, D*y0, D, D);
      for(int i=1; i<anz; ++i){
        next=weg[i];
        int y=next/spalten;
        int x=next%spalten;
        if(i==0) {x0=x; y0=y;}
        g.drawLine(D/2+D*x0, D/2+D*y0, D/2+D*x, D/2+D*y);
        x0=x; y0=y;
      }
    }
  }

  @Override
  public void mousePressed(MouseEvent e) {
    int z=e.getY()/D;
    int s=e.getX()/D;
    System.out.println("Plan für z="+z+" s="+s+"...");
    plan=graph.getPlan(spalten*z+s);
    System.out.println("...erstellt");
  }

  @Override
  public void mouseMoved(MouseEvent e) {
    int z=e.getY()/D;
    int s=e.getX()/D;
    if(s>=spalten || z>=zeilen) return;
    int n=spalten*z+s;
    if(n!=zielnr){
      if(plan!=null){
        int a=plan.getAbstand(n);
        if(a<0) setToolTipText("Kein Weg");
        else setToolTipText("Weg="+a);
      }
      zielnr=n;
      repaint();
    }
    //System.out.println("Zielnummer="+zielnr);
  }

  public void mouseReleased(MouseEvent e) {}
  public void mouseEntered(MouseEvent e) {}
  public void mouseClicked(MouseEvent e) {}
  public void mouseExited(MouseEvent e) {}
  public void mouseDragged(MouseEvent e) {}

  public static void main(String[] args){
    JFrame jf=new JFrame("Labyrinth");
    Labyrinth la=new Labyrinth(30,40);
    jf.getContentPane().add(la);
    jf.pack();
    jf.setVisible(true);
    jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
  }
}
